/**********************************************
*  Classes:   TransformNode
*  Desc:      Defines a transform node
*			  in the Scene Graph
*  Author:    Vaios Kalpias-Ilias (C) 2008-2009
***********************************************/

#include "TransformNode.h"
#include "CdnRenderer.h"
using namespace std;

//-------------------------------------------------
/**
* Ctor
*/
TransformNode::TransformNode() 
 : m_vScale(1.0f, 1.0f, 1.0f), 
   m_bUpdateProperties(false),
   m_bUpdateLights(false)
{
	
}
//-------------------------------------------------
/**
* Dtor
*/
TransformNode::~TransformNode()
{
	m_Properties.clear();
	m_lLights.clear();
}

//----------------------------------------------
/**
* Update properties
*/
void TransformNode::UpdateProperties()
{
	if (!m_pParent) return;

	if (m_pParent->DerivesFromTransform())
	{
		TransformNode* p = static_cast<TransformNode*>(m_pParent);
	
		if (!p->m_bUpdateProperties) return;

		PropertyMap::iterator it;
		// for all the parent's properties
		for (it = p->m_Properties.begin();
			it != p->m_Properties.end();
			++it)
		{
			// if the property exists then use this one
			// otherwise use the parent's property
			NodePropertyPtr thisP(GetProperty(it->second->GetType()));
			if (!thisP)
			{
				AddProperty(it->second);
			}
		}
	}
}
//----------------------------------------------
/**
* Update lights
*/
void TransformNode::UpdateLights()
{
	if (!m_pParent) return;

	if (m_pParent->DerivesFromTransform())
	{
		TransformNode* p = static_cast<TransformNode*>(m_pParent);
	
		if (!p->m_bUpdateLights) return;

		unsigned int maxLights = CdnRenderer::GetMaxLights();
		
		LightList::iterator it;
		// for all the parent's lights
		for (it = p->m_lLights.begin();
			it != p->m_lLights.end();
			++it)
		{
			if (m_lLights.size() >= maxLights) return;
			// add them to this list
			m_lLights.push_back(*it);
		}
	}
}
//-------------------------------------------------
/**
* Pre update step
*/
void TransformNode::PreUpdate()
{
	// inherit transforms
	if (m_pParent)
	{		
		if (m_pParent->DerivesFromTransform())
		{
			TransformNode* p = static_cast<TransformNode*>(m_pParent);
			m_qGlobalRotation = (p->GetGlobalRotationQuat() *
								m_qLocalRotation).Normalized();
			
			m_vGlobalPos = p->GetGlobalTranslation() 
				+ p->GetGlobalRotationQuat().Rotate(m_vLocalPos);
		}
		else
		{
			m_qGlobalRotation = m_qLocalRotation;
			m_vGlobalPos = m_vLocalPos;
		}		
	}
	else
	{
		m_qGlobalRotation = m_qLocalRotation;
		m_vGlobalPos = m_vLocalPos;
	}
	
	ResetBoundingBox();
	m_BoundingBox.Move(m_vGlobalPos, m_qGlobalRotation);
	//m_BoundingBox.Update(m_vGlobalPos, GetGlobalRotation(), m_vScale.x);

	UpdateProperties();
	UpdateLights();
}
//-------------------------------------------------
/**
* Post update step
*/
void TransformNode::PostUpdate()
{
	m_bUpdateProperties = false;	
	m_bUpdateLights = false;	

	// grow parent's bounding box if necessary
	
	
	if (m_pParent)
	{
		if (m_pParent->DerivesFromTransform())
		{
			TransformNode* p = static_cast<TransformNode*>(m_pParent);
			BoundingBox& pBox = p->m_BoundingBox;
			//BoundingBox moved(m_BoundingBox);
			//moved.Move(p->GetGlobalRotationQuat().Rotate(m_vLocalPos), p->GetGlobalRotationQuat()*m_qLocalRotation);
			//mth::Vector3 localPos = p->m_qLocalRotation.Rotate(m_vLocalPos);
			//BoundingBox moved(m_BoundingBox);
			//moved.Scale(m_vScale);
			//moved.Move(m_vLocalPos, m_qLocalRotation);
			pBox.Grow(m_BoundingBox);
		}
	}

	
	
}

//----------------------------------------------
/**
* Adds a property to the map
*/
void TransformNode::AddProperty(NodePropertyPtr p)
{
	if (!p) return;
	
	// if the property exists replace it
	PropertyMap::iterator it = m_Properties.find(p->GetType());
	if ( it != m_Properties.end())
	{
		it->second = p;
	}
	else
	{
		m_Properties.insert(make_pair(p->GetType(), p));
	}
	
	m_bUpdateProperties = true;
}
//----------------------------------------------
/**
* Gets a property
*/
NodePropertyPtr TransformNode::GetProperty(NodeProperty::PropertyType type)
{
	
	PropertyMap::iterator it = m_Properties.find(type);
	if ( it != m_Properties.end())
	{
		return it->second;
	}
	
	
	return NodePropertyPtr();
	
	//return m_Properties[type];
}
//----------------------------------------------
/**
* Removes a property
*/
void TransformNode::RemoveProperty(NodeProperty::PropertyType type)
{
	PropertyMap::iterator it = m_Properties.find(type);
	if ( it != m_Properties.end())
	{
		m_Properties.erase(it);
	}

}
//----------------------------------------------
/**
* Sorts lights according to distance from position
*/
void TransformNode::SortLights()
{
	
}